package org.maxgroundstation.groundstation.view;

import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TimeZone;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

import org.maxgroundstation.groundstation.GroundStation;
import org.maxgroundstation.groundstation.GroundStationEvent;
import org.maxgroundstation.groundstation.GroundStationListener;
import org.maxgroundstation.groundstation.comm.service.Service;
import org.maxgroundstation.groundstation.comm.service.gps.GpsDataLogger;
import org.maxgroundstation.groundstation.comm.service.gps.GpsService;
import org.maxgroundstation.groundstation.comm.service.gps.PointOfInterest;

/**
 * The GPS data panel.
 * @author Scott Davis
 * 
 * Copyright (C) 2010  Scott Davis
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@SuppressWarnings("serial")
public class GpsDataPanel extends JPanel implements GroundStationListener {
    
    // Static members.
    private static final String POI_DIR = System.getProperty("user.home") + File.separator + 
            "max_groundstation" + File.separator + "poi";
    
    // Data members
    private GroundStation gs;
    private JButton gpsLogButton;
    private JButton pointOfInterestButton;
    private DateFormat dateFormatter1;
    private DateFormat dateFormatter2;
    
    /**
     * Constructor
     * @param gs the ground station.
     */
    public GpsDataPanel(GroundStation gs) {
        super();
        
        // Initialize data members.
        this.gs = gs;
        dateFormatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
        dateFormatter1.setTimeZone(TimeZone.getTimeZone("UTC"));
        dateFormatter2 = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ssz");
        dateFormatter2.setTimeZone(TimeZone.getTimeZone("UTC"));
        
        // Set layout.
        setLayout(new GridLayout(2, 1));
        
        // Set border.
        setBorder(new TitledBorder("GPS Data Collection"));
        
        // Create GPS logging panel.
        JPanel gpsLoggingPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
        add(gpsLoggingPanel);
        
        // Create start/stop GPS logging button.
        gpsLogButton = new JButton("Start GPS Logging");
        gpsLogButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                updateGpsLogging();
            }
        });
        gpsLogButton.setEnabled(false);
        gpsLogButton.setToolTipText("Start logging GPS data to a file in " + 
                "the max_groundstation/gps_data folder.");
        gpsLoggingPanel.add(gpsLogButton);
        
        // Create point of interest panel.
        JPanel pointOfInterestPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
        add(pointOfInterestPanel);
        
        // Create point of interest button.
        pointOfInterestButton = new JButton("Create Point of Interest");
        pointOfInterestButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                createPointOfInterest();
            }
        });
        pointOfInterestButton.setEnabled(false);
        pointOfInterestButton.setToolTipText("Create a point of interest at this location.");
        pointOfInterestPanel.add(pointOfInterestButton);
        
        // Add as ground station listener.
        gs.addGroundStationListener(this);
    }
    
    /**
     * Gets the rover gps service .
     * @return gps service or null if none.
     */
    private GpsService getGpsService() {
        return (GpsService) gs.getServiceComm().getService(GpsService.SERVICE_ID);
    }
    
    /**
     * Starts or stops the GPS logging.
     */
    private void updateGpsLogging() {
        if (gs.getServiceComm().hasService(GpsService.SERVICE_ID)) {
            GpsDataLogger logger = getGpsService().getLogger();
            if (logger.isLogging()) {
                logger.stopLogging();
                gpsLogButton.setText("Start GPS Logging");
                gpsLogButton.setToolTipText("Start logging GPS data to a file in " + 
                        "the max_groundstation/gps_data folder.");
            }
            else {
                boolean successful = logger.startLogging();
                if (successful) gpsLogButton.setText("Stop GPS Logging");
                gpsLogButton.setToolTipText("Stop logging GPS data.");
            }
        }
    }
    
    /** 
     * Creates a new point of interest.
     */
    private void createPointOfInterest() {
        GpsService gpsService = getGpsService();
        if (gpsService != null) {
            PointOfInterest poi = new PointOfInterest();
            
            try {
                // Set time stamp.
                Date timestamp = dateFormatter1.parse(gpsService.getGpsMap().get("time"));
                poi.setTimestamp(timestamp);
                
                // Set latitude.
                double latitude = Double.parseDouble(gpsService.getGpsMap().get("lat"));
                poi.setLatitude(latitude);
                
                // Set longitude.
                double longitude = Double.parseDouble(gpsService.getGpsMap().get("lon"));
                poi.setLongitude(longitude);
                
                // Copy all current video images.
                int videoServiceNum = VideoDisplayUtil.getVideoServicesNames().size();
                Map<String, ImageIcon> videoImages = new HashMap<String, ImageIcon>(videoServiceNum);
                Iterator<String> i = VideoDisplayUtil.getVideoServicesNames().iterator();
                while (i.hasNext()) {
                    String videoServiceName = i.next();
                    Service videoService = gs.getServiceComm().getServiceByName(videoServiceName);
                    if (gs.getServiceComm().isServiceSubscribed(videoService)) {
                        videoImages.put(videoServiceName, VideoDisplayUtil.getCurrentVideoImage(
                                videoServiceName));
                    }
                }
                
                // Open point of interest dialog to get name and description.
                JFrame topFrame = (JFrame) getTopLevelAncestor();
                boolean createPoi = PointOfInterestCreationDialog.openDialog(topFrame, poi);
                
                if (createPoi) {
                    // Save all copied video snap shots and record file names in point of interest.
                    Iterator<String> j = videoImages.keySet().iterator();
                    while (j.hasNext()) {
                        String videoServiceName = j.next();
                        String filename = savePOIVideoSnapShot(videoServiceName, timestamp);
                        if (filename != null) poi.addSnapshotFileName(filename);
                    }
                    
                    // Add point of interest to list of points of interest.
                    gpsService.addPointOfInterest(poi);
                    
                    // Clear video image list for garbage collection.
                    videoImages.clear();
                    videoImages = null;
                }
            }
            catch (Exception e) {
                e.printStackTrace(System.err);
            }
        }
    }
    
    /**
     * Save a point of interest video snap shot.
     * @param videoServiceName the video service name.
     * @param timestamp the time stamp to use.
     * @return the file name the snap shot is saved to.
     */
    private String savePOIVideoSnapShot(String videoServiceName, Date timestamp) {
        String filename = null;
        ImageIcon videoImage = VideoDisplayUtil.getCurrentVideoImage(videoServiceName);
        if (videoImage != null) {
            BufferedImage bImage = new BufferedImage(videoImage.getIconWidth(), videoImage.getIconHeight(),
                    BufferedImage.TYPE_3BYTE_BGR);
            Graphics2D g2 = bImage.createGraphics();
            g2.drawImage(videoImage.getImage(), 0, 0, null);
            g2.dispose();
            
            try {
                File defaultDir = new File(POI_DIR);
                if (!defaultDir.exists()) {
                    defaultDir.mkdirs();
                }
                filename = dateFormatter2.format(timestamp) + "_" + videoServiceName + ".jpg";
                ImageIO.write(bImage, "jpg", new File(POI_DIR + File.separator + filename));
                
            }
            catch (IOException e) {
                e.printStackTrace(System.err);
            }
        }
        
        return filename;
    }
    
    @Override
    public void groundStationUpdate(GroundStationEvent event) {
        // If services initialized from robot, check for GPS service.
        GroundStation gs = (GroundStation) event.getSource();
        if (GroundStationEvent.SERVICES_INITIALIZED.equals(event.getType())) {
            if (gs.getServiceComm().hasService(GpsService.SERVICE_ID)) {
                // Enable GPS logging button.
                gpsLogButton.setEnabled(true);
                
                // Enable point of interest button.
                pointOfInterestButton.setEnabled(true);
            }
        }
        else if (GroundStationEvent.SERVICES_CLOSED.equals(event.getType())) {
            // Disable GPS Logging button.
            gpsLogButton.setEnabled(false);
            gpsLogButton.setText("Start GPS Logging");
            gpsLogButton.setToolTipText("Start logging GPS data to a file in " + 
                    "the max_groundstation/gps_data folder.");
            
            // Disable point of interest button.
            pointOfInterestButton.setEnabled(false);
        }
    }
}